package gui;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import data.ArpTemplate;
import data.ChordTemplate;
import data.Comm;
import data.DeviceProperties;
import data.EchoTemplate;
import data.RandomTemplate;
import data.Serializable;

@SuppressWarnings("serial")
public class DevicePanel extends JPanel implements ActionListener, PopupMenuListener, ChangeListener {
	private JLabel lblComPort, lblMidiChannelIn, lblMidiChannelOut;
	private JComboBox cmbComPort, cmbMidiChannelIn, cmbMidiChannelOut;
	private JButton btnUpdateDevice;
	//private Color fgColor, bgColor;
	//private Font font;
	private Vector<CommPortIdentifier> comPorts;
	private DeviceProperties devProps;
	private String path = System.getProperty("user.dir") + System.getProperty("file.separator") + "devprops.dat";
	private boolean init = true;
	private Comm comm;
	//private ArpTemplate template;
	private JTabbedPane tabPane;
	
	public DevicePanel(Color fgColor, Color bgColor, Font font, DeviceProperties devProps, RandomTemplate rtemplate,
			EchoTemplate etemplate, ChordTemplate ctemplate, ArpTemplate atemplate, JTabbedPane tabPane) {
		super();
		this.tabPane = tabPane;
		this.tabPane.addChangeListener(this);
		/*this.fgColor = fgColor;
		this.bgColor = bgColor;
		this.font = font;*/
		//this.template = template;		
		this.setBackground(bgColor);
		//this.setBorder(BorderFactory.createLineBorder(fgColor))
		
		lblComPort = new JLabel("PORT: ");
		lblComPort.setForeground(fgColor);
		lblComPort.setFont(font);
		this.add(lblComPort);
		
		btnUpdateDevice = new JButton("UPDATE");
		btnUpdateDevice.setBackground(bgColor);
		btnUpdateDevice.setForeground(fgColor);
		btnUpdateDevice.setFont(font);
		btnUpdateDevice.addActionListener(this);
		btnUpdateDevice.setEnabled(false);
		
		cmbComPort = new JComboBox();
		cmbComPort.setBackground(bgColor);
		cmbComPort.setForeground(fgColor);
		cmbComPort.setFont(font);
		cmbComPort.addActionListener(this);
		cmbComPort.addPopupMenuListener(this);
		updateComPorts();
		this.add(cmbComPort);
		
		lblMidiChannelIn = new JLabel("MIDI CH. IN: ");
		lblMidiChannelIn.setForeground(fgColor);
		lblMidiChannelIn.setFont(font);
		this.add(lblMidiChannelIn);
		
		cmbMidiChannelIn = new JComboBox();
		cmbMidiChannelIn.setBackground(bgColor);
		cmbMidiChannelIn.setForeground(fgColor);
		cmbMidiChannelIn.setFont(font);
		cmbMidiChannelIn.addActionListener(this);
		for (int i = 1; i < 17; i++) cmbMidiChannelIn.addItem("" + i);
		this.add(cmbMidiChannelIn);
		
		lblMidiChannelOut = new JLabel("MIDI CH. OUT: ");
		lblMidiChannelOut.setForeground(fgColor);
		lblMidiChannelOut.setFont(font);
		this.add(lblMidiChannelOut);
		
		cmbMidiChannelOut = new JComboBox();
		cmbMidiChannelOut.setBackground(bgColor);
		cmbMidiChannelOut.setForeground(fgColor);
		cmbMidiChannelOut.setFont(font);
		cmbMidiChannelOut.addActionListener(this);
		for (int i = 1; i < 17; i++) cmbMidiChannelOut.addItem("" + i);
		this.add(cmbMidiChannelOut);
		
		this.add(btnUpdateDevice);
		
		this.devProps = devProps;
		readDeviceProperties();
		cmbMidiChannelIn.setSelectedItem("" + devProps.getMidiIn());
		cmbMidiChannelOut.setSelectedItem("" + devProps.getMidiOut());
		Serializable templates[] = {devProps, rtemplate, etemplate, ctemplate, atemplate};
		comm = new Comm(null, templates);
		
		init = false;
	}
	
	private void updateComPorts() { // init has to be false 
		comPorts = new Vector<CommPortIdentifier>();
		Enumeration<?> ports = CommPortIdentifier.getPortIdentifiers(); // All ports
		while (ports.hasMoreElements()) {
			CommPortIdentifier com = (CommPortIdentifier) ports.nextElement();
			if (com.getPortType() == CommPortIdentifier.PORT_SERIAL) comPorts.add(com);
		}
		if (cmbComPort.getItemCount() > 0) cmbComPort.removeAllItems();
		init = true;
		for (CommPortIdentifier com: comPorts) cmbComPort.addItem(com.getName());
		System.out.println("updateComports()");
	}
	
	private void readDeviceProperties() {
		File file = new File(path);
		if (file.exists()) {
			try {
				FileInputStream fis = new FileInputStream(file);
				devProps.deserialize(fis);
				tabPane.setSelectedIndex(devProps.getMode());
			} 
			catch (FileNotFoundException fne) {
				fne.printStackTrace();
			}  
		}
	}
	
	private void writeDeviceProperties() {
		File file = new File(path);
		try {
			FileOutputStream fos = new FileOutputStream(file);
			devProps.serialize(fos);
		} 
		catch (FileNotFoundException fne) {
			fne.printStackTrace();
		} 
	}

	@Override
	public void actionPerformed(ActionEvent ae) {
		if (ae.getSource() == cmbComPort) {
			System.out.println("Comport1");
			if (!init) {
				System.out.println("Comport2");
				//if (!initcp) {
					//System.out.println("Comport3");
					String name = (String) cmbComPort.getSelectedItem();
					boolean found = false;
					int i = 0;
					while (!found && i < comPorts.size()) {
						if (name.equals(comPorts.get(i).getName())) found = true;
						i++;
					}
					comm.setPortId(comPorts.get(i-1));
					btnUpdateDevice.setEnabled(true);
				//}
			}
		}
		else if (ae.getSource() == cmbMidiChannelIn) {
			if (!init) {
				devProps.setMidiIn(Integer.parseInt((String) cmbMidiChannelIn.getSelectedItem()));
				writeDeviceProperties();
			}
		}
		else if (ae.getSource() == cmbMidiChannelOut) {
			if (!init) {
				devProps.setMidiOut(Integer.parseInt((String) cmbMidiChannelOut.getSelectedItem()));
				writeDeviceProperties();
			}
			else {
				init = false;
			}
		}
		else if (ae.getSource() == btnUpdateDevice) {
			if (comm.getPortId() != null) {
				try {
					comm.send();
				} 
				catch (PortInUseException piue) {
					btnUpdateDevice.setEnabled(false);
 					piue.printStackTrace();
				}
			}
		}
	}

	@Override
	public void popupMenuCanceled(PopupMenuEvent pme) {}

	@Override
	public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {}

	@Override
	public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {
		System.out.println("popup");
		init = true;
		updateComPorts();
		init = false;
	}
	
	@Override
	public void stateChanged(ChangeEvent ce) {
		tabPane = (JTabbedPane) ce.getSource();
		devProps.setMode(tabPane.getSelectedIndex());
		writeDeviceProperties();
		System.out.println("Mode: " + devProps.getMode());
	}
}
